//
// Created by zhfayuan on 2021/6/9.
//

#ifndef GBRELAYERVER_RELAYSVR_H
#define GBRELAYERVER_RELAYSVR_H

#include <thread>
#include <mutex>
#include <vector>
#include <array>
#include <unordered_map>
#include <condition_variable>

#include "GBRelayConfig.h"
#include "hiredis.h"
#include "GbtProxyKit.h"
#include "RelayTerminal.h"
#include "GBGwChannel.h"


#define SIGNAL_TOPIC_PUSH_SERVICE "push.service"
//#define SIGNAL_TOPIC_CLIENT_PREFIX "signal.cli"
//#define SIGNAL_TOPIC_CLIENT_OFF_PREFIX "signal.offcli"
#define SIGNAL_TOPIC_PUBLIC_REQUEST "signal.request"
#define SIGNAL_TOPIC_PUBLIC_RESPONSE "signal.response"
#define MEDIA_TOPIC_PUBLIC_NOTIFY "media.notify"
//#define SIGNAL_TOPIC_MEDIASERVER_REGIST_REQUEST "register.mediaserver"
//#define SIGNAL_TOPIC_PLAYBACKSERVER_REGIST_REQUEST "register.playbackserver"
//#define SIGNAL_TOPIC_INNER_NOTIFY "inner.notify"

#define TOPCI_GB_DEFAULT "gb28181.request"

struct RedisMessage
{
    std::string topic;
    std::string arg1;
    std::string arg2;
};

struct ObjStatus
{
    bool  record_en;
    uint16_t temperature;
    uint16_t battery;
    uint16_t rssi;
    uint64_t disk_free;
    uint64_t disk_total;
    ObjStatus()
    {
        battery = 0;
        rssi = 0;
        temperature = 0;
        disk_free = 0;
        disk_total = 0;
        record_en = false;
    }
};

struct ProxyObj
{
    bool   living;
    bool   on_pos;
    uint64_t  uid;
    uint32_t index;
    std::string name;
    bool channel_online;
    uint32_t gb28181_id;

    ObjStatus  status;
    std::shared_ptr<GBGwChannel>  channel;
};


class GBGwServer:public enable_shared_from_this<GBGwServer>, public RelayTermHandler, public RelayStreamHandler
        ,public gbt::GbtProxyMessageHandler,public gbt::GbtProxyAgentSink,public gbt::GbtProxyPlaybackHandler,public GBGwChannelHandler
{
public:
    GBGwServer();
    virtual  ~GBGwServer();
private:
    std::shared_ptr<RelayTerminal> _terminal;
private:
    GBT_Server  m_server;
    std::map<uint64_t,std::shared_ptr<ProxyObj>> _proxyObjs;
private:
    void subThreadEntry();
    void workThreadEntry();
    void pubThreadEntry();
    void connThreadEntry();
private:
    std::mutex _subLock;
    std::condition_variable _subCond;
    std::shared_ptr<thread> _subThread;
    volatile bool _subAborth;
    volatile bool _subRun;

private:
    std::mutex _workLock;
    std::condition_variable _workCond;
    std::shared_ptr<thread> _workThread;
    volatile bool _workAborth;
    volatile bool _workRun;
    std::list<std::pair<std::string,std::string>> _lstWorkMsg;
    //std::list<std::string> _lstWorkMsg;
private:
    std::mutex _pubLock;
    std::condition_variable _pubCond;
    std::shared_ptr<thread> _pubThread;
    volatile bool _pubAborth;
    volatile bool _pubRun;
    std::list<std::pair<std::string,std::string>> _lstpubMsg;


private:
    std::mutex _connLock;
    std::condition_variable _connCond;
    std::shared_ptr<thread> _connThread;
    volatile bool _connAbort;
    volatile bool _connRun;
    volatile bool _termAbort;
private:
    std::string _redis_ip;
    uint32_t   _redis_port;
    std::string _media_ip;
    uint32_t _media_port;
    uint32_t _index;

private:
    std::mutex _vlock;
    std::mutex _alock;
protected:
    //RelayStreamHandler

    virtual void onRelayAudioData(uint64_t id,char *data,uint32_t length,uint64_t  pts) final;
    virtual void onRelayVideoData(uint64_t id,char *data,uint32_t length,uint64_t  pts,bool key,bool hevc) final;
    virtual void onRelayProviderOffPosition(uint64_t uid,uint64_t room,uint64_t index) final;
    virtual void onRelayProviderOnPosition(uint64_t uid,uint64_t room,uint64_t index) final;
    //RelayTermHandler
    virtual void onRelayConnectionLost() final;
protected:
    virtual void onConnectStatus(int status, int64_t clock);
    virtual void handlePtzCommand(int id, const char* deviceID, const GBT_PtzCommand& cmd);
    virtual void handleTeleBoot(int id, const char* deviceID, GBT_TeleBoot& boot);
    virtual void handleForceKeyFrame(int id, const char* deviceID);
    virtual void handleZoom(int id, const char* deviceID, GBT_DragZoomMode zoomMode, const GBT_DragZoom& dragZoom);
    /// 有应答命令.
    virtual bool handleRecordCmd(int id, const GBT_Command& req, const GBT_RecordCmd& cmd);
    virtual bool handleGuardCmd(int id, const GBT_Command& req, const GBT_GuardCmd& cmd);
    virtual bool handleAlarmCmd(int id, const GBT_Command& req, const GBT_AlarmCmd& cmd);
    virtual bool handleSetHomePosition(int id, const GBT_Command& req, const GBT_HomePosition& cmd);
    virtual bool handleDeviceConfig(int id, const GBT_Command& req, const GBT_DeviceConfig& config);
    /// 查询.
    virtual bool handleQueryDeviceInfo(int id, const GBT_Command& req, GBT_DeviceInfo& info);
    virtual bool handleQueryDeviceStatus(int id, const GBT_Command& req, GBT_DeviceStatus& status);
    virtual bool handleQueryBasicParam(int id, const GBT_Command& req, GBT_BasicParam& config);
    virtual bool handleQueryVideoParamOpt(int id, const GBT_Command& req, GBT_VideoParamOpt& config);
    virtual bool handleQueryVideoParamConfig(int id, const GBT_Command& req, GBT_VideoParamConfig& config);
    virtual bool handleQueryAudioParamOpt(int id, const GBT_Command& req, GBT_AudioParamOpt& config);
    virtual bool handleQueryAudioParamConfig(int id, const GBT_Command& req, GBT_AudioParamConfig& config);
    virtual int handleQueryRecordInfo(int id, const GBT_Command& req, const GBT_RecordInfoQuery& query, GBT_RecordInfo* records, int size);
    virtual int handleQueryAlarm(int id, const GBT_Command& req, const GBT_AlarmQuery& query, GBT_Alarm* alarms, int size);
    virtual int handleQueryPreset(int id, const GBT_Command& req, const GBT_PresetQuery& query, GBT_Preset* presets, int size);
    virtual bool handleQueryMobilePosition(int id, const GBT_Command& req, const GBT_MobilePositionQuery& query);
    virtual bool handleSW(int id, const GBT_Command& req, const GBT_DeviceSwitch& sw);
    /// custom defined message
    virtual bool handleMessage(int id, const GBT_Command& req, GBT_Command& resp);
    //GbtDevicePlaybackHandler
    virtual int openPlayback(const GBT_RecordUrl& record, double speed, MStreamSource** ppStream);
    virtual void closePlayback(MStreamSource* pStream);

protected:
    virtual void onBeginPlay(uint32_t index);
    virtual void onEndPlay(uint32_t index);
private:
    void postPubMessage(std::string key,std::string value);
public:
    void stopServer();
    void startServer(struct GBRelayConfig &config);
};
#endif //FACESERVER_FACESERVER_H
